﻿using Google.Protobuf.WellKnownTypes;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using SkiaSharp;
using static System.Net.Mime.MediaTypeNames;
using JsonModel;
using static System.Formats.Asn1.AsnWriter;
using System.Net;
using Newtonsoft.Json;
using System.IO;
using System.Security.Cryptography.X509Certificates;

namespace RgChannelBot
{
    public class ImageDrawer
    {
        public static readonly float Height;
        public static readonly float Scale;
        public static readonly float Width;
        public static SKFont Impact;
        public static SKFont YaHei;
        public static SKFont YaHei_BOLD;
        public static SKFont Emoji;
        public SKSurface Surface;
        private static readonly string BackgroundImagePath = Path.Combine(Environment.CurrentDirectory, "bkgd.png");
        private static SKBitmap BackgroundImage;

        static ImageDrawer()
        {
            using (FileStream fs = File.OpenRead(BackgroundImagePath))
            {
                BackgroundImage = SKBitmap.Decode(fs);
                Width = BackgroundImage.Width;
                Height = BackgroundImage.Height;
                Scale = Width * Height / 10000;
            }
            var index = SKFontManager.Default.FontFamilies.ToList().IndexOf("微软雅黑");
            YaHei = new SKFont(SKFontManager.Default.GetFontStyles(index).CreateTypeface(1));
            YaHei_BOLD = new SKFont(SKFontManager.Default.GetFontStyles(index).CreateTypeface(2));
            index = SKFontManager.Default.FontFamilies.ToList().IndexOf("Impact");
            Impact = new SKFont(SKFontManager.Default.GetFontStyles(index).CreateTypeface(0));
        }

        public ImageDrawer(string title)
        {
            Surface = SKSurface.Create(new SKImageInfo((int)Width, (int)Height, SKColorType.Rgba8888, SKAlphaType.Premul));
            Surface.Canvas.Clear();
            Surface.Canvas.DrawBitmap(BackgroundImage, 0, 0);
            var paint = new SKPaint()
            {
                TextSize = 0.7f * Scale,
                MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Solid, 4f),
                Color = new SKColor(205, 102, 0),
                Typeface = YaHei_BOLD.Typeface,
                TextAlign = SKTextAlign.Center,
                IsAntialias = true
            };
            float x = Width / 2f;
            float y = Height * 0.15f;
            paint.BreakText(title, Width, out float x_width);
            paint.Shader = SKShader.CreateLinearGradient(
                new SKPoint(x + x_width * 0.25f, y), new SKPoint(x + x_width * 0.75f, y), new SKColor[] { new SKColor(58, 95, 205), new SKColor(224, 102, 255) }, SKShaderTileMode.Mirror);
            Surface.Canvas.DrawText(title, Width / 2f, Height * 0.15f, paint);
        }

        public byte[] GetArray()
        {
            using (var s = Surface.Snapshot())
            {
                using (var x = s.Encode())
                {
                    return x.ToArray();
                }
            }
        }
    }

    public static class ProfileDrawer
    {
        private static void AddLine(this SKCanvas c, string key, string value, float x, float y, int line, SKColor? valuecolor = null)
        {
            var txt = new SKPaint()
            {
                Color = new SKColor(10, 10, 20),
                IsAntialias = true,
                TextSize = ImageDrawer.Scale * 0.22f,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface
            };
            var val = new SKPaint()
            {
                Color = valuecolor ?? new SKColor(47, 79, 79),
                IsAntialias = true,
                TextSize = ImageDrawer.Scale * 0.22f,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface
            };
            key = $"{key}: ";
            y += ImageDrawer.Height * 0.04f * (line - 1);
            c.DrawText(key, x, y, txt);
            txt.BreakText(key, ImageDrawer.Width, out float x_width);
            c.DrawText(value, x + x_width, y, val);
        }

        public static async Task<byte[]> Draw(PlayerData data, int server, bool hideID = true)
        {
            var drawer = new ImageDrawer("玩家档案");
            var c = drawer.Surface.Canvas;
            float x = ImageDrawer.Width * 0.1f;
            float y = ImageDrawer.Height * 0.23f;
            float x1 = ImageDrawer.Width * 0.68f;
            if (data.UserId.Contains("@steam"))
            {
                try
                {
                    var image = await GetAvatar(data.UserId.Replace("@steam", ""));
                    if (image != null)
                    {
                        var size = new SKSize(image.Width * 2f, image.Height * 2f);
                        var rect = new SKRect()
                        {
                            Location = new SKPoint(x1, y),
                            Size = size
                        };
                        SKPath path = new SKPath();
                        path.MoveTo(x1, y);
                        path.LineTo(x1 + size.Width, y);
                        path.LineTo(x1 + size.Width, y + size.Height);
                        path.LineTo(x1, y + size.Height);
                        path.LineTo(x1, y);
                        SKPaint border = new SKPaint()
                        {
                            IsStroke = true,
                            Color = new SKColor(100, 100, 100),
                            MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Solid, 5f),
                            StrokeWidth = 5f,
                        };
                        c.DrawPath(path, border);
                        c.DrawImage(image, rect);
                    }
                }
                catch(Exception e)
                {
                    Log.Warn("无法获取头像：" + e.Message);
                }
            }
            var onl = new SKPaint()
            {
                Color = new SKColor(20, 20, 20),
                IsAntialias = true,
                TextSize = ImageDrawer.Scale * 0.25f,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                TextAlign = SKTextAlign.Center
            };
            c.DrawText("[                    ]", ImageDrawer.Width * 0.8f, y + ImageDrawer.Height * 0.3f, onl);
            onl.Color = data.OnlineData == null ? new SKColor(100, 0, 0) : new SKColor(0, 100, 0);
            var span = DateTime.Now - data.LastLogin;
            string day = $"{span.Days} 天前";
            if (span.Days > 31)
                day = $"{Math.Floor(span.Days / 30.0)} 个月前";
            if (span.Days > 365)
                day = $"很久以前";
            string status = data.OnlineData == null ? day : $"在线：#{server}";
            c.DrawText(status, ImageDrawer.Width * 0.8f, y + ImageDrawer.Height * 0.3f, onl);
            if (data.OnlineData != null)
            {
                var o = data.OnlineData;
                int line = 0;
                float y2 = y + ImageDrawer.Height * 0.34f;
                c.AddLine("ID", o.Id.ToString(), x1, y2, ++line);
                c.AddLine("正在扮演", o.RoleName, x1, y2, ++line, new SKColor((uint)ColorTranslator.FromHtml(o.RoleColorHex).ToArgb()));
                c.AddLine("禁言", $"{(o.Muted ? "是" : "否")}", x1, y2, ++line, o.Muted ? new SKColor(100, 0, 0) : new SKColor(0, 100, 0));
                c.AddLine("广播禁言", $"{(o.IcomMuted ? "是" : "否")}", x1, y2, ++line, o.IcomMuted ? new SKColor(100, 0, 0) : new SKColor(0, 100, 0));
            }
            var name = new SKPaint()
            {
                Color = new SKColor(85, 26, 139),
                IsAntialias = true,
                TextSize = ImageDrawer.Scale * 0.5f,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Solid, 2f),
            };
            name.BreakText(data.Nickname, ImageDrawer.Width, out float length);
            name.TextSize *= 1 - (length * 0.4f / ImageDrawer.Height);
            c.DrawText(data.Nickname, x, y + ImageDrawer.Height * 0.07f, name);
            var txt = new SKPaint()
            {
                Color = new SKColor(100, 100, 100),
                IsAntialias = true,
                TextSize = ImageDrawer.Scale * 0.25f,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface
            };
            if (!hideID)
                c.DrawText(data.UserId, x, y + ImageDrawer.Height * 0.115f, txt);
            txt.Color = new SKColor(10, 10, 20);
            int i = 0;
            y += ImageDrawer.Height * 0.16f;
            int level = data.OnlineData == null ? data.Level : data.OnlineData.Level;
            int exp = data.OnlineData == null ? data.Experience : data.OnlineData.Experience;
            int mvp = data.OnlineData == null ? data.Mvp : data.OnlineData.Mvp;
            int points = data.OnlineData == null ? data.Points : data.OnlineData.Points;
            int max = 200 + ((level - 1) * 300);
            c.AddLine("等级", $"{level} ({exp} / {max})", x, y, ++i);
            c.AddLine("MVP", $"{mvp}", x, y, ++i);
            c.AddLine("积分", $"{points}", x, y, ++i, new SKColor(184, 134, 11));
            c.AddLine("赞助称号", $"{(data.DonatorBadge == null ? "未拥有" : data.DonatorBadge.Value.Text)}", x, y, ++i,
                data.DonatorBadge == null ? null : new SKColor((uint)Extensions.GetColor(data.DonatorBadge.Value.Color).ToArgb()));
            for (int j = 0; j < data.SpecialBadges.Length && j < 6; j++)
            {
                c.AddLine($"专属称号#{j + 1}", data.SpecialBadges[j].Text, x, y, ++i,
                    new SKColor((uint)Extensions.GetColor(data.SpecialBadges[j].Color).ToArgb()));
            }
            string time = "";
            //预留
            SKColor color = new SKColor(100, 0, 0);
            if (data.Reservation != null)
            {
                time = data.Reservation.Value.Year <= 2014 ? "永久" : $"截至 {data.Reservation.Value:yyyy-MM-dd}";
                color = data.Reservation.Value.Year <= 2014 ? new SKColor(218, 165, 32) : new SKColor(0, 139, 139);
            }
            c.AddLine("预留位", data.Reservation == null ? "未拥有" : time, x, y, ++i, color);
            //彩虹
            color = new SKColor(100, 0, 0);
            if (data.RainbowBadge != null)
            {
                time = data.RainbowBadge.Value.Year <= 2014 ? "永久" : $"截至 {data.RainbowBadge.Value:yyyy-MM-dd}";
                color = data.RainbowBadge.Value.Year <= 2014 ? new SKColor(218, 165, 32) : new SKColor(0, 139, 139);
            }
            c.AddLine("彩虹称号", data.RainbowBadge == null ? "未拥有" : time, x, y, ++i, color);
            //MVP音乐
            color = new SKColor(100, 0, 0);
            if (data.MvpMusic != null)
            {
                time = data.MvpMusic.Value.Key.Replace(".ogg", "");
                color = new SKColor(0, 139, 139);
                if (data.MvpMusic.Value.Value.Year <= 2014)
                {
                    color = new SKColor(218, 165, 32);
                    time += "（永久）";
                }
            }
            c.AddLine("MVP音乐", data.MvpMusic == null ? "未拥有" : time, x, y, ++i, color);
            //进服消息
            color = new SKColor(100, 0, 0);
            if (data.JoinMessage != null)
            {
                time = data.JoinMessage.Value.Key;
                color = new SKColor(0, 139, 139);
                if (data.JoinMessage.Value.Value.Year <= 2014)
                {
                    color = new SKColor(218, 165, 32);
                    time += "（永久）";
                }
            }
            c.AddLine("进服消息", data.JoinMessage == null ? "未拥有" : time, x, y, ++i, color);
            using (var s = drawer.Surface.Snapshot())
            {
                using (var x2 = s.Encode())
                {
                    return x2.ToArray();
                }
            }
        }

        private static async Task<SKImage?> GetAvatar(string steam64id)
        {
            HttpClient cli = new();
            var rep = await cli.GetAsync(
                $"https://api.steampowered.com/ISteamUser/GetPlayerSummaries/v0002/?key=85098B537A05746574721DE9A23DA4EA&steamids={steam64id}");
            Root? pi = JsonConvert.DeserializeObject<Root>(await rep.Content.ReadAsStringAsync());
            if (pi != null)
            {
                rep = await cli.GetAsync(pi.response.players.First().avatarfull);
                return SKImage.FromBitmap(SKBitmap.Decode(await rep.Content.ReadAsStreamAsync()));
            }
            return null;
        }

        public class Response
        {
            public List<PlayersItem> players { get; set; }
        }

        public class Root
        {
            public Response response { get; set; }
        }

        public class PlayersItem
        {
            public string steamid { get; set; }
            public int communityvisibilitystate { get; set; }
            public int profilestate { get; set; }
            public string personaname { get; set; }
            public int commentpermission { get; set; }
            public string profileurl { get; set; }
            public string avatar { get; set; }
            public string avatarmedium { get; set; }
            public string avatarfull { get; set; }
            public string avatarhash { get; set; }
            public int lastlogoff { get; set; }
            public int personastate { get; set; }
            public string realname { get; set; }
            public string primaryclanid { get; set; }
            public int timecreated { get; set; }
            public int personastateflags { get; set; }
            public string loccountrycode { get; set; }
            public string locstatecode { get; set; }
            public int loccityid { get; set; }
        }
    }

    public class ServerQueryDrawer
    {
        public ImageDrawer Drawer = new ImageDrawer("服务器列表");
        private readonly float x_margin = ImageDrawer.Width * 0.05f;

        public ServerQueryDrawer()
        {
        }

        public enum NoInfo
        {
            Offline, Unknown
        }

        public void AddServerNoInfo(int serverId, string servername, NoInfo ni)
        {
            int servers = serverId > 8 ? serverId - 8 : serverId;
            var c = Drawer.Surface.Canvas;
            var p1 = new SKPaint()
            {
                TextSize = 0.3f * ImageDrawer.Scale,
                Color = new SKColor(100, 0, 0),
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                TextAlign = SKTextAlign.Left,
                IsAntialias = true
            };
            float y = ImageDrawer.Height * 0.2f * (servers > 4 ? servers - 4 : servers);
            float x = Math.Floor((float)servers / 5) == 0 ? x_margin : (x_margin + ImageDrawer.Width) * 0.5f;
            DrawBorder(serverId, false, x,y,out float width, out float height);
            DrawServerName(servername, x, y, width, height);
            DrawPlayerCount(-1, 0, x, y, width, height);
            string status = ni == NoInfo.Unknown ? "未知" : "离线";
            if (ni == NoInfo.Unknown)
            {
                p1.Color = new SKColor(139, 69, 19);
            }
            c.DrawText(status, x + 0.05f * width, y + height * 0.90f, p1);
        }

        public void AddServerWithInfo(int serverId, string servername, ServerData sd)
        {
            int servers = serverId > 8 ? serverId - 8 : serverId;
            var c = Drawer.Surface.Canvas;
            var p1 = new SKPaint()
            {
                TextSize = 0.28f * ImageDrawer.Scale,
                Color = new SKColor(0, 100, 0),
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                TextAlign = SKTextAlign.Left,
                IsAntialias = true
            };
            float y = ImageDrawer.Height * 0.2f * (servers > 4 ? servers - 4 : servers);
            float x = Math.Floor((float)servers / 5) == 0 ? x_margin : (x_margin + ImageDrawer.Width) * 0.5f;
            DrawBorder(serverId,true, x,y,out float width, out float height);
            DrawServerName(servername, x, y, width, height);
            DrawPlayerCount(sd.Players, sd.MaxPlayers, x, y, width, height);
            string status = sd.RoundTime == -1 ? "等待玩家中" : $"已开局{sd.RoundTime}分钟";
            if (sd.RoundTime >= 0)
            {
                p1.Color = new SKColor(205, 85, 85);
            }
            c.DrawText(status, x + 0.04f * width, y + height * 0.90f, p1);
        }

        private void DrawPlayerCount(int player, int maxplayer, float x, float y, float width, float height)
        {
            var c = Drawer.Surface.Canvas;
            var srv_player = new SKPaint()
            {
                TextSize = 0.2f * ImageDrawer.Scale,
                Color = new SKColor(40, 40, 40),
                Typeface = ImageDrawer.Impact.Typeface,
                TextAlign = SKTextAlign.Right,
                IsAntialias = true,
            };
            var srv_player2 = new SKPaint()
            {
                TextSize = 0.3f * ImageDrawer.Scale,
                Color = new SKColor(40, 40, 40),
                Typeface = ImageDrawer.Impact.Typeface,
                TextAlign = SKTextAlign.Right,
                IsAntialias = true,
            };
            c.DrawText($"{(maxplayer == 0 ? "A" : maxplayer)}", x + width * 0.97f, y + height * 0.92f, srv_player);
            srv_player.BreakText(maxplayer.ToString(), width, out float s_width);
            c.DrawText("/", x + width * 0.97f - s_width, y + height * 0.92f, srv_player2);
            srv_player2.BreakText("/", width, out float s_width2);
            srv_player2.TextSize *= 1.5f;
            SKColor color = new(0, 150, 0);
            float percent = (float)player / (maxplayer == 0 ? 1 : maxplayer);
            if (percent < 0)
                color = new SKColor(40, 40, 40);
            if (percent >= 0.7)
                color = new SKColor(205, 102, 29);
            if (percent >= 1)
                color = new SKColor(170, 0, 0);
            srv_player2.Color = color;
            c.DrawText($"{(player < 0 ? "N" : player)}", x + width * 0.97f - s_width - s_width2, y + height * 0.92f, srv_player2);
        }

        private void DrawBorder(int id, bool online, float x, float y,out float width, out float height)
        {
            var c = Drawer.Surface.Canvas;
            var rect_paint = new SKPaint()
            {
                Color = online ? new SKColor(0, 30, 0, 20) : new SKColor(30, 0, 0, 20),
                StrokeWidth = 30,
                Style = SKPaintStyle.Fill,
                StrokeJoin = SKStrokeJoin.Round,
            };
            var bck_txt_paint = new SKPaint()
            {
                TextSize = ImageDrawer.Scale * 0.6f,
                Color = online ? new SKColor(0, 100, 0, 20) : new SKColor(100, 0, 0, 20),
                TextAlign = SKTextAlign.Center,
                Typeface = ImageDrawer.Impact.Typeface,
            };
            //边框部分
            width = (ImageDrawer.Width - 3 * x_margin) * 0.5f;
            height = ImageDrawer.Height * 0.18f;
            c.DrawRoundRect(new SKRoundRect(
                new SKRect(x, y, x + width, y + height), 10f), rect_paint);
            rect_paint.Color = online ? new SKColor(0, 100, 0, 255) : new SKColor(100, 0, 0, 255);
            c.DrawRoundRect(new SKRoundRect(
                            new SKRect(x, y, x + width * 0.01f, y + height), 10f), rect_paint);
            c.DrawRect(new SKRect(x + width * 0.005f, y, x + width * 0.02f, y + height), rect_paint);
            c.DrawText($"#{id}", x + width * 0.5f, y + height * 0.66666f, bck_txt_paint);
        }

        private void DrawServerName(string servername, float x, float y, float width, float height)
        {
            var c = Drawer.Surface.Canvas;
            var svr_txt_paint = new SKPaint()
            {
                TextSize = ImageDrawer.Scale * 0.35f,
                Color = new SKColor(40, 40, 40, 255),
                TextAlign = SKTextAlign.Left,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                FilterQuality = SKFilterQuality.High,
                IsAntialias = true,
                MaskFilter = SKMaskFilter.CreateBlur(SKBlurStyle.Solid, 3f),
            };
            var svr_border_paint = new SKPaint()
            {
                TextSize = ImageDrawer.Scale * 0.35f,
                Color = new SKColor(240, 240, 255),
                TextAlign = SKTextAlign.Left,
                Typeface = ImageDrawer.YaHei_BOLD.Typeface,
                FilterQuality = SKFilterQuality.High,
                IsAntialias = true,
                IsStroke = true,
                StrokeWidth = 2f
            };
            c.DrawText(servername, x + 0.05f * width, y + height * 0.35f, svr_txt_paint);
            c.DrawText(servername, x + 0.05f * width, y + height * 0.35f, svr_border_paint);
        }
    }
}